package com.shiwaixiangcun.monitor.service.impl;

import com.rabbit.spring.data.search.SearchOperator;
import com.rabbit.spring.data.search.Searchable;
import com.shiwaixiangcun.core.domain.Dictionary;
import com.shiwaixiangcun.core.exceptions.MonkeyException;
import com.shiwaixiangcun.core.plugin.dto.MonkeyDto;
import com.shiwaixiangcun.core.service.BaseServiceImpl;
import com.shiwaixiangcun.core.service.DictionaryService;
import com.shiwaixiangcun.core.utils.MonkeyUtils;
import com.shiwaixiangcun.monitor.domain.User;
import com.shiwaixiangcun.monitor.domain.WorkOrder;
import com.shiwaixiangcun.monitor.domain.WorkOrderCategory;
import com.shiwaixiangcun.monitor.domain.WorkOrderTimeoutRule;
import com.shiwaixiangcun.monitor.dto.TimeOutDateDto;
import com.shiwaixiangcun.monitor.dto.WorkOrderTimeoutRuleDto;
import com.shiwaixiangcun.monitor.enums.WorkOrderStatus;
import com.shiwaixiangcun.monitor.repository.WorkOrderRepository;
import com.shiwaixiangcun.monitor.repository.WorkOrderTimeoutRuleRepository;
import com.shiwaixiangcun.monitor.service.UserService;
import com.shiwaixiangcun.monitor.service.WorkOrderCategoryService;
import com.shiwaixiangcun.monitor.service.WorkOrderTimeoutRuleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Created by Administrator on 2017/11/23.
 */
@Service
@Transactional
public class WorkOrderTimeoutRuleServiceImpl extends BaseServiceImpl<WorkOrderTimeoutRule, Long> implements WorkOrderTimeoutRuleService {

    @Autowired
    private WorkOrderTimeoutRuleRepository workOrderTimeoutRuleRepository;
    @Autowired
    private WorkOrderCategoryService workOrderCategoryService;
    @Autowired
    private UserService userService;
    @Autowired
    private WorkOrderRepository workOrderRepository;
    @Autowired
    private DictionaryService dictionaryService;

    @Override
    public List<WorkOrderTimeoutRuleDto> ruleList() {
        return toDto(findAll());
    }

    @Override
    public void ruleAdd(MonkeyDto monkeyDto) {
        WorkOrderTimeoutRule rule = buildAddRule(monkeyDto);
        repeatCheck(rule);
        save(rule);
    }

    @Override
    public void ruleRemove(Long id) {
        delete(id);
    }

    @Override
    public void execTimeOutJob() {
        List<WorkOrderTimeoutRule> ruleList = workOrderTimeoutRuleRepository.findAll();
        List<WorkOrderCategory> categoryList = workOrderRepository.getUsedCategory();
        Set<WorkOrder> timeOutList = new HashSet<>();

        for (WorkOrderCategory category : categoryList) {
            WorkOrderTimeoutRule rule = findTimeOutRule(category, ruleList, categoryList);
            if (MonkeyUtils.isNotEmpty(rule)) {
                Date date = getTimeOutDate(rule);
                List<WorkOrder> ids = workOrderRepository.getNeedSetTimeOutWorkOrderIds(category, date, WorkOrderStatus.Accepted);
                timeOutList.addAll(ids);
            }
        }
        if (MonkeyUtils.isNotEmpty(timeOutList)) {
            for (WorkOrder workOrder : timeOutList) {
                workOrder.setTimeout(true);
            }
            workOrderRepository.save(timeOutList);
        }
    }

    @Override
    public List<TimeOutDateDto> getTimeOutDateList() {
        List<Dictionary> list = dictionaryService.findByDictionaryType(WorkOrderTimeoutRule.WORK_ORDER_TIME_OUT_DIC);
        List<TimeOutDateDto> rs = new ArrayList<>();
        TimeOutDateDto dateDto;
        for (Dictionary dictionary : list) {
            dateDto = new TimeOutDateDto();
            dateDto.setName(dictionary.getName());
            dateDto.setValue(Integer.valueOf(dictionary.getValue()));
            rs.add(dateDto);
        }
        return rs;
    }

    private Date getTimeOutDate(WorkOrderTimeoutRule rule) {
        int hours = rule.getTime();
        return MonkeyUtils.plusHours(new Date(), -hours);
    }

//    private List<WorkOrderCategory> getEnableCategory() {
//        Searchable searchable = Searchable.newSearchable();
//        searchable.addSearchFilter("status", SearchOperator.eq, Status.ENABLE);
//        return workOrderCategoryService.findAllWithNoPageNoSort(searchable);
//    }


    private WorkOrderTimeoutRule findTimeOutRule(WorkOrderCategory category, List<WorkOrderTimeoutRule> ruleList, List<WorkOrderCategory> categoryList) {
        if (MonkeyUtils.isEmpty(category)) {
            return null;
        }
        WorkOrderTimeoutRule rule = getUsableRule(category, ruleList);
        if (MonkeyUtils.isNotEmpty(rule)) {
            return rule;
        } else {
//            category = getUsedParentCategory(category.getParentId(), categoryList);
            category = workOrderCategoryService.findOne(category.getParentId());
            return findTimeOutRule(category, ruleList, categoryList);
        }
    }

    private WorkOrderCategory getUsedParentCategory(Long id, List<WorkOrderCategory> categoryList) {
        for (WorkOrderCategory category : categoryList) {
            if (category.getId().equals(id)) {
                return category;
            }
        }
        return null;
    }

    private WorkOrderTimeoutRule getUsableRule(WorkOrderCategory category, List<WorkOrderTimeoutRule> ruleList) {
        WorkOrderTimeoutRule rs = null;
        for (WorkOrderTimeoutRule rule : ruleList) {
            if (rule.getCategory().equals(category)) {
                if (MonkeyUtils.isEmpty(rs)) {
                    rs = rule;
                } else {
                    if (rule.getTime() < rs.getTime()) {
                        rs = rule;
                    }
                }
            }
        }
        return rs;
    }

    private WorkOrderTimeoutRule buildAddRule(MonkeyDto monkeyDto) {
        WorkOrderTimeoutRule rule = new WorkOrderTimeoutRule();
        rule.setStatus(WorkOrderStatus.Accepted);
        rule.setTime(monkeyDto.getInteger("time"));
        WorkOrderCategory category = workOrderCategoryService.findOne(monkeyDto.getLong("categoryId"));
        if (MonkeyUtils.isEmpty(category)) {
            throw new MonkeyException("该工单分类不存在");
        }
        User user = userService.findOne(monkeyDto.getLong("userId"));
        if (MonkeyUtils.isEmpty(user)) {
            throw new MonkeyException("该通知人不存在");
        }
        rule.setCategory(category);
        rule.setUser(user);
        return rule;
    }

    private void repeatCheck(WorkOrderTimeoutRule rule) {
        WorkOrderTimeoutRule rs = workOrderTimeoutRuleRepository.findByCategoryAndTimeAndUser(rule.getCategory(), rule.getTime(), rule.getUser());
        if (MonkeyUtils.isNotEmpty(rs)) {
            throw new MonkeyException("存在相同规则");
        }
    }

    private List<WorkOrderTimeoutRuleDto> toDto(List<WorkOrderTimeoutRule> list) {
        List<WorkOrderTimeoutRuleDto> dtoList = new ArrayList<>();
        WorkOrderTimeoutRuleDto dto;
        for (WorkOrderTimeoutRule rule : list) {
            dto = new WorkOrderTimeoutRuleDto();
            dto.setId(rule.getId());
            dto.setCategoryName(rule.getCategory().getName());
            dto.setStatus(rule.getStatus());
            dto.setTime(getDateStr(rule.getTime())); // 查询字典
            dto.setUserName(rule.getUser().getName());
            dtoList.add(dto);
        }
        return dtoList;
    }

    private String getDateStr(Integer time) {
        Searchable searchable = Searchable.newSearchable();
        searchable.addSearchFilter("value", SearchOperator.eq, time.toString());
        searchable.addSearchFilter("type", SearchOperator.eq, WorkOrderTimeoutRule.WORK_ORDER_TIME_OUT_DIC);
        List<Dictionary> rs = dictionaryService.findAll(searchable).getContent();
        if (rs.size() != 1) {
            throw new MonkeyException("字典查询错误");
        }
        return rs.get(0).getName();
    }
}
